﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using HslCommunication.BasicFramework;
using HslCommunication.Core;
using HslCommunication.Core.Net;
using HslCommunication.Reflection;

namespace HslCommunication.Profinet.Omron
{
	/// <summary>
	/// 欧姆龙的HostLink协议的实现，基于Tcp实现，地址支持示例 DM区:D100; CIO区:C100; Work区:W100; Holding区:H100; Auxiliary区: A100<br />
	/// Implementation of Omron's HostLink protocol, based on tcp protocol, address support example DM area: D100; CIO area: C100; Work area: W100; Holding area: H100; Auxiliary area: A100
	/// </summary>
	/// <remarks>
	/// 感谢 深圳～拾忆 的测试，地址可以携带站号信息，例如 s=2;D100 
	/// <br />
	/// <note type="important">
	/// 如果发现串口线和usb同时打开才能通信的情况，需要按照如下的操作：<br />
	/// 串口线不是标准的串口线，电脑的串口线的235引脚分别接PLC的329引脚，45线短接，就可以通讯，感谢 深圳-小君(QQ932507362)提供的解决方案。
	/// </note>
	/// </remarks>
	/// <example>
	/// 欧姆龙的地址参考如下：
	/// 地址支持的列表如下：
	/// <list type="table">
	///   <listheader>
	///     <term>地址名称</term>
	///     <term>地址代号</term>
	///     <term>示例</term>
	///     <term>地址进制</term>
	///     <term>字操作</term>
	///     <term>位操作</term>
	///     <term>备注</term>
	///   </listheader>
	///   <item>
	///     <term>DM Area</term>
	///     <term>D</term>
	///     <term>D100,D200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>CIO Area</term>
	///     <term>C</term>
	///     <term>C100,C200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>Work Area</term>
	///     <term>W</term>
	///     <term>W100,W200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>Holding Bit Area</term>
	///     <term>H</term>
	///     <term>H100,H200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>Auxiliary Bit Area</term>
	///     <term>A</term>
	///     <term>A100,A200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	/// </list>
	/// </example>
	// Token: 0x02000062 RID: 98
	public class OmronHostLinkOverTcp : NetworkDeviceSoloBase
	{
		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.#ctor" />
		// Token: 0x06000804 RID: 2052 RVA: 0x0002B310 File Offset: 0x00029510
		public OmronHostLinkOverTcp()
		{
			base.ByteTransform = new ReverseWordTransform();
			base.WordLength = 1;
			base.ByteTransform.DataFormat = DataFormat.CDAB;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronCipNet.#ctor(System.String,System.Int32)" />
		// Token: 0x06000805 RID: 2053 RVA: 0x0002B364 File Offset: 0x00029564
		public OmronHostLinkOverTcp(string ipAddress, int port)
		{
			base.ByteTransform = new ReverseWordTransform();
			base.WordLength = 1;
			base.ByteTransform.DataFormat = DataFormat.CDAB;
			this.IpAddress = ipAddress;
			this.Port = port;
		}

		/// <summary>
		/// Specifies whether or not there are network relays. Set “80” (ASCII: 38,30) 
		/// when sending an FINS command to a CPU Unit on a network.Set “00” (ASCII: 30,30) 
		/// when sending to a CPU Unit connected directly to the host computer.
		/// </summary>
		// Token: 0x17000172 RID: 370
		// (get) Token: 0x06000806 RID: 2054 RVA: 0x0002B3C7 File Offset: 0x000295C7
		// (set) Token: 0x06000807 RID: 2055 RVA: 0x0002B3CF File Offset: 0x000295CF
		public byte ICF { get; set; } = 0;

		/// <inheritdoc cref="P:HslCommunication.Profinet.Omron.OmronFinsNet.DA2" />
		// Token: 0x17000173 RID: 371
		// (get) Token: 0x06000808 RID: 2056 RVA: 0x0002B3D8 File Offset: 0x000295D8
		// (set) Token: 0x06000809 RID: 2057 RVA: 0x0002B3E0 File Offset: 0x000295E0
		public byte DA2 { get; set; } = 0;

		/// <inheritdoc cref="P:HslCommunication.Profinet.Omron.OmronFinsNet.SA2" />
		// Token: 0x17000174 RID: 372
		// (get) Token: 0x0600080A RID: 2058 RVA: 0x0002B3E9 File Offset: 0x000295E9
		// (set) Token: 0x0600080B RID: 2059 RVA: 0x0002B3F1 File Offset: 0x000295F1
		public byte SA2 { get; set; }

		/// <inheritdoc cref="P:HslCommunication.Profinet.Omron.OmronFinsNet.SID" />
		// Token: 0x17000175 RID: 373
		// (get) Token: 0x0600080C RID: 2060 RVA: 0x0002B3FA File Offset: 0x000295FA
		// (set) Token: 0x0600080D RID: 2061 RVA: 0x0002B402 File Offset: 0x00029602
		public byte SID { get; set; } = 0;

		/// <summary>
		/// The response wait time sets the time from when the CPU Unit receives a command block until it starts 
		/// to return a response.It can be set from 0 to F in hexadecimal, in units of 10 ms.
		/// If F(15) is set, the response will begin to be returned 150 ms (15 × 10 ms) after the command block was received.
		/// </summary>
		// Token: 0x17000176 RID: 374
		// (get) Token: 0x0600080E RID: 2062 RVA: 0x0002B40B File Offset: 0x0002960B
		// (set) Token: 0x0600080F RID: 2063 RVA: 0x0002B413 File Offset: 0x00029613
		public byte ResponseWaitTime { get; set; } = 48;

		/// <summary>
		/// PLC设备的站号信息<br />
		/// PLC device station number information
		/// </summary>
		// Token: 0x17000177 RID: 375
		// (get) Token: 0x06000810 RID: 2064 RVA: 0x0002B41C File Offset: 0x0002961C
		// (set) Token: 0x06000811 RID: 2065 RVA: 0x0002B424 File Offset: 0x00029624
		public byte UnitNumber { get; set; }

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.Read(System.String,System.UInt16)" />
		// Token: 0x06000812 RID: 2066 RVA: 0x0002B430 File Offset: 0x00029630
		[HslMqttApi("ReadByteArray", "")]
		public override OperateResult<byte[]> Read(string address, ushort length)
		{
			byte station = (byte)HslHelper.ExtractParameter(ref address, "s", (int)this.UnitNumber);
			OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildReadCommand(address, length, false);
			bool flag = !operateResult.IsSuccess;
			OperateResult<byte[]> result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(this.PackCommand(station, operateResult.Content));
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = OperateResult.CreateFailedResult<byte[]>(operateResult2);
				}
				else
				{
					OperateResult<byte[]> operateResult3 = OmronHostLinkOverTcp.ResponseValidAnalysis(operateResult2.Content, true);
					bool flag3 = !operateResult3.IsSuccess;
					if (flag3)
					{
						result = OperateResult.CreateFailedResult<byte[]>(operateResult3);
					}
					else
					{
						result = OperateResult.CreateSuccessResult<byte[]>(operateResult3.Content);
					}
				}
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.Write(System.String,System.Byte[])" />
		// Token: 0x06000813 RID: 2067 RVA: 0x0002B4D4 File Offset: 0x000296D4
		[HslMqttApi("WriteByteArray", "")]
		public override OperateResult Write(string address, byte[] value)
		{
			byte station = (byte)HslHelper.ExtractParameter(ref address, "s", (int)this.UnitNumber);
			OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildWriteWordCommand(address, value, false);
			bool flag = !operateResult.IsSuccess;
			OperateResult result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(this.PackCommand(station, operateResult.Content));
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = operateResult2;
				}
				else
				{
					OperateResult<byte[]> operateResult3 = OmronHostLinkOverTcp.ResponseValidAnalysis(operateResult2.Content, false);
					bool flag3 = !operateResult3.IsSuccess;
					if (flag3)
					{
						result = operateResult3;
					}
					else
					{
						result = OperateResult.CreateSuccessResult();
					}
				}
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.Read(System.String,System.UInt16)" />
		// Token: 0x06000814 RID: 2068 RVA: 0x0002B568 File Offset: 0x00029768
		[DebuggerStepThrough]
		public override Task<OperateResult<byte[]>> ReadAsync(string address, ushort length)
		{
			OmronHostLinkOverTcp.<ReadAsync>d__28 <ReadAsync>d__ = new OmronHostLinkOverTcp.<ReadAsync>d__28();
			<ReadAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
			<ReadAsync>d__.<>4__this = this;
			<ReadAsync>d__.address = address;
			<ReadAsync>d__.length = length;
			<ReadAsync>d__.<>1__state = -1;
			<ReadAsync>d__.<>t__builder.Start<OmronHostLinkOverTcp.<ReadAsync>d__28>(ref <ReadAsync>d__);
			return <ReadAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.Write(System.String,System.Byte[])" />
		// Token: 0x06000815 RID: 2069 RVA: 0x0002B5BC File Offset: 0x000297BC
		[DebuggerStepThrough]
		public override Task<OperateResult> WriteAsync(string address, byte[] value)
		{
			OmronHostLinkOverTcp.<WriteAsync>d__29 <WriteAsync>d__ = new OmronHostLinkOverTcp.<WriteAsync>d__29();
			<WriteAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
			<WriteAsync>d__.<>4__this = this;
			<WriteAsync>d__.address = address;
			<WriteAsync>d__.value = value;
			<WriteAsync>d__.<>1__state = -1;
			<WriteAsync>d__.<>t__builder.Start<OmronHostLinkOverTcp.<WriteAsync>d__29>(ref <WriteAsync>d__);
			return <WriteAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.ReadBool(System.String,System.UInt16)" />
		// Token: 0x06000816 RID: 2070 RVA: 0x0002B610 File Offset: 0x00029810
		[HslMqttApi("ReadBoolArray", "")]
		public override OperateResult<bool[]> ReadBool(string address, ushort length)
		{
			byte station = (byte)HslHelper.ExtractParameter(ref address, "s", (int)this.UnitNumber);
			OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildReadCommand(address, length, true);
			bool flag = !operateResult.IsSuccess;
			OperateResult<bool[]> result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<bool[]>(operateResult);
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(this.PackCommand(station, operateResult.Content));
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = OperateResult.CreateFailedResult<bool[]>(operateResult2);
				}
				else
				{
					OperateResult<byte[]> operateResult3 = OmronHostLinkOverTcp.ResponseValidAnalysis(operateResult2.Content, true);
					bool flag3 = !operateResult3.IsSuccess;
					if (flag3)
					{
						result = OperateResult.CreateFailedResult<bool[]>(operateResult3);
					}
					else
					{
						result = OperateResult.CreateSuccessResult<bool[]>(Enumerable.ToArray<bool>(Enumerable.Select<byte, bool>(operateResult3.Content, (byte m) => m != 0)));
					}
				}
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.Write(System.String,System.Boolean[])" />
		// Token: 0x06000817 RID: 2071 RVA: 0x0002B6E4 File Offset: 0x000298E4
		[HslMqttApi("WriteBoolArray", "")]
		public override OperateResult Write(string address, bool[] values)
		{
			byte station = (byte)HslHelper.ExtractParameter(ref address, "s", (int)this.UnitNumber);
			OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildWriteWordCommand(address, Enumerable.ToArray<byte>(Enumerable.Select<bool, byte>(values, (bool m) => m ? 1 : 0)), true);
			bool flag = !operateResult.IsSuccess;
			OperateResult result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(this.PackCommand(station, operateResult.Content));
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = operateResult2;
				}
				else
				{
					OperateResult<byte[]> operateResult3 = OmronHostLinkOverTcp.ResponseValidAnalysis(operateResult2.Content, false);
					bool flag3 = !operateResult3.IsSuccess;
					if (flag3)
					{
						result = operateResult3;
					}
					else
					{
						result = OperateResult.CreateSuccessResult();
					}
				}
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.ReadBool(System.String,System.UInt16)" />
		// Token: 0x06000818 RID: 2072 RVA: 0x0002B7A4 File Offset: 0x000299A4
		[DebuggerStepThrough]
		public override Task<OperateResult<bool[]>> ReadBoolAsync(string address, ushort length)
		{
			OmronHostLinkOverTcp.<ReadBoolAsync>d__32 <ReadBoolAsync>d__ = new OmronHostLinkOverTcp.<ReadBoolAsync>d__32();
			<ReadBoolAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool[]>>.Create();
			<ReadBoolAsync>d__.<>4__this = this;
			<ReadBoolAsync>d__.address = address;
			<ReadBoolAsync>d__.length = length;
			<ReadBoolAsync>d__.<>1__state = -1;
			<ReadBoolAsync>d__.<>t__builder.Start<OmronHostLinkOverTcp.<ReadBoolAsync>d__32>(ref <ReadBoolAsync>d__);
			return <ReadBoolAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Omron.OmronFinsNet.Write(System.String,System.Boolean[])" />
		// Token: 0x06000819 RID: 2073 RVA: 0x0002B7F8 File Offset: 0x000299F8
		[DebuggerStepThrough]
		public override Task<OperateResult> WriteAsync(string address, bool[] values)
		{
			OmronHostLinkOverTcp.<WriteAsync>d__33 <WriteAsync>d__ = new OmronHostLinkOverTcp.<WriteAsync>d__33();
			<WriteAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
			<WriteAsync>d__.<>4__this = this;
			<WriteAsync>d__.address = address;
			<WriteAsync>d__.values = values;
			<WriteAsync>d__.<>1__state = -1;
			<WriteAsync>d__.<>t__builder.Start<OmronHostLinkOverTcp.<WriteAsync>d__33>(ref <WriteAsync>d__);
			return <WriteAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc />
		// Token: 0x0600081A RID: 2074 RVA: 0x0002B84A File Offset: 0x00029A4A
		public override string ToString()
		{
			return string.Format("OmronHostLinkOverTcp[{0}:{1}]", this.IpAddress, this.Port);
		}

		/// <summary>
		/// 将普通的指令打包成完整的指令
		/// </summary>
		/// <param name="station">PLC的站号信息</param>
		/// <param name="cmd">fins指令</param>
		/// <returns>完整的质量</returns>
		// Token: 0x0600081B RID: 2075 RVA: 0x0002B868 File Offset: 0x00029A68
		private byte[] PackCommand(byte station, byte[] cmd)
		{
			cmd = SoftBasic.BytesToAsciiBytes(cmd);
			byte[] array = new byte[18 + cmd.Length];
			array[0] = 64;
			array[1] = SoftBasic.BuildAsciiBytesFrom(station)[0];
			array[2] = SoftBasic.BuildAsciiBytesFrom(station)[1];
			array[3] = 70;
			array[4] = 65;
			array[5] = this.ResponseWaitTime;
			array[6] = SoftBasic.BuildAsciiBytesFrom(this.ICF)[0];
			array[7] = SoftBasic.BuildAsciiBytesFrom(this.ICF)[1];
			array[8] = SoftBasic.BuildAsciiBytesFrom(this.DA2)[0];
			array[9] = SoftBasic.BuildAsciiBytesFrom(this.DA2)[1];
			array[10] = SoftBasic.BuildAsciiBytesFrom(this.SA2)[0];
			array[11] = SoftBasic.BuildAsciiBytesFrom(this.SA2)[1];
			array[12] = SoftBasic.BuildAsciiBytesFrom(this.SID)[0];
			array[13] = SoftBasic.BuildAsciiBytesFrom(this.SID)[1];
			array[array.Length - 2] = 42;
			array[array.Length - 1] = 13;
			cmd.CopyTo(array, 14);
			int num = (int)array[0];
			for (int i = 1; i < array.Length - 4; i++)
			{
				num ^= (int)array[i];
			}
			array[array.Length - 4] = SoftBasic.BuildAsciiBytesFrom((byte)num)[0];
			array[array.Length - 3] = SoftBasic.BuildAsciiBytesFrom((byte)num)[1];
			string @string = Encoding.ASCII.GetString(array);
			Console.WriteLine(@string);
			return array;
		}

		/// <summary>
		/// 验证欧姆龙的Fins-TCP返回的数据是否正确的数据，如果正确的话，并返回所有的数据内容
		/// </summary>
		/// <param name="response">来自欧姆龙返回的数据内容</param>
		/// <param name="isRead">是否读取</param>
		/// <returns>带有是否成功的结果对象</returns>
		// Token: 0x0600081C RID: 2076 RVA: 0x0002B9B8 File Offset: 0x00029BB8
		public static OperateResult<byte[]> ResponseValidAnalysis(byte[] response, bool isRead)
		{
			bool flag = response.Length >= 27;
			OperateResult<byte[]> result;
			if (flag)
			{
				int num;
				bool flag2 = int.TryParse(Encoding.ASCII.GetString(response, 19, 4), out num);
				if (flag2)
				{
					byte[] array = null;
					bool flag3 = response.Length > 27;
					if (flag3)
					{
						array = SoftBasic.HexStringToBytes(Encoding.ASCII.GetString(response, 23, response.Length - 27));
					}
					bool flag4 = num > 0;
					if (flag4)
					{
						result = new OperateResult<byte[]>
						{
							ErrorCode = num,
							Content = array
						};
					}
					else
					{
						result = OperateResult.CreateSuccessResult<byte[]>(array);
					}
				}
				else
				{
					result = new OperateResult<byte[]>(string.Concat(new string[]
					{
						"Parse error code failed, [",
						Encoding.ASCII.GetString(response, 19, 4),
						"] ",
						Environment.NewLine,
						"Source Data: ",
						response.ToHexString(' ')
					}));
				}
			}
			else
			{
				result = new OperateResult<byte[]>(StringResources.Language.OmronReceiveDataError + " Source Data: " + response.ToHexString(' '));
			}
			return result;
		}
	}
}
